package net.vinote.sosa.rmi;

import java.security.KeyPair;
import java.security.PublicKey;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import net.vinote.smart.socket.lang.QuicklyConfig;
import net.vinote.smart.socket.lang.StringUtils;
import net.vinote.smart.socket.protocol.P2PProtocolFactory;
import net.vinote.smart.socket.protocol.enums.ReturnCodeEnum;
import net.vinote.smart.socket.protocol.p2p.client.P2PClientMessageProcessor;
import net.vinote.smart.socket.protocol.p2p.message.BaseMessageFactory;
import net.vinote.smart.socket.protocol.p2p.message.LoginAuthReq;
import net.vinote.smart.socket.protocol.p2p.message.LoginAuthResp;
import net.vinote.smart.socket.protocol.p2p.message.RemoteInterfaceMessageResp;
import net.vinote.smart.socket.protocol.p2p.message.SecureSocketMessageReq;
import net.vinote.smart.socket.protocol.p2p.message.SecureSocketMessageResp;
import net.vinote.smart.socket.security.RSA;
import net.vinote.smart.socket.service.filter.SmartFilter;
import net.vinote.smart.socket.service.filter.impl.FlowControlFilter;
import net.vinote.smart.socket.service.session.Session;
import net.vinote.smart.socket.transport.nio.NioQuickClient;

import org.apache.commons.collections.MapUtils;

public class RmiClient {
	private Map<String, RmiUnit> sessionMap = new ConcurrentHashMap<String, RmiUnit>();

	public Session getSession(String url) {
		if (sessionMap.containsKey(url)) {
			return sessionMap.get(url).processor.getSession();
		}
		synchronized (url) {
			if (sessionMap.containsKey(url)) {
				return sessionMap.get(url).processor.getSession();
			}
			try {
				RmiUnit unit = connectAndAuth(url);
				sessionMap.put(url, unit);
				return unit.processor.getSession();
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}

	private RmiUnit connectAndAuth(String url) throws Exception {
		String[] array = url.split(":");
		Properties properties = new Properties();
		properties.put(SecureSocketMessageResp.class.getName(), "");
		properties.put(LoginAuthResp.class.getName(), "");
		properties.put(RemoteInterfaceMessageResp.class.getName(), "");
		BaseMessageFactory.getInstance().loadFromProperties(properties);
		QuicklyConfig config = new QuicklyConfig(false);
		P2PProtocolFactory factory = new P2PProtocolFactory();
		config.setProtocolFactory(factory);
		P2PClientMessageProcessor processor = new P2PClientMessageProcessor();
		config.setProcessor(processor);
		config.setFilters(new SmartFilter[] { new FlowControlFilter() });
		config.setHost(array[0]);
		config.setPort(Integer.parseInt(array[1]));
		config.setTimeout(3000);
		NioQuickClient client = new NioQuickClient(config);
		client.start();

		// 发送鉴权消息
		SecureSocketMessageReq publicKeyReq = new SecureSocketMessageReq();
		KeyPair keyPair = RSA.generateKeyPair();
		publicKeyReq.setRsaPublicKey(keyPair.getPublic().getEncoded());
		SecureSocketMessageResp resp = (SecureSocketMessageResp) processor
				.getSession().sendWithResponse(publicKeyReq);

		byte[] pubKey = RSA
				.decode(keyPair.getPrivate(), resp.getRsaPublicKey());
		PublicKey serverPubKey = RSA.generatePublicKey(pubKey);
		processor.getSession().setAttribute(StringUtils.SECRET_KEY,
				RSA.decode(serverPubKey, resp.getEncryptedKey()));

		LoginAuthReq loginReq = new LoginAuthReq(processor.getSession()
				.getAttribute(StringUtils.SECRET_KEY, byte[].class));
		loginReq.setUsername("zjw");
		loginReq.setPassword("aa");
		LoginAuthResp loginResp = (LoginAuthResp) processor.getSession()
				.sendWithResponse(loginReq);
		if (StringUtils.equals(ReturnCodeEnum.SUCCESS.getCode(),
				loginResp.getReturnCode())) {
			return new RmiUnit(processor, client);
		}
		throw new RuntimeException(loginResp.getReturnDesc());
	}

	public void destory() {
		if (MapUtils.isEmpty(sessionMap)) {
			return;
		}
		for (RmiUnit unit : sessionMap.values()) {
			unit.client.shutdown();
		}
		sessionMap.clear();
	}

	private class RmiUnit {
		P2PClientMessageProcessor processor;
		NioQuickClient client;

		public RmiUnit(P2PClientMessageProcessor processor,
				NioQuickClient client) {
			this.processor = processor;
			this.client = client;
		}

	}
}
